package cn.stimd.spring.context.annotation;

import cn.stimd.spring.beans.factory.annotation.AnnotatedBeanDefinition;
import cn.stimd.spring.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import cn.stimd.spring.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor;
import cn.stimd.spring.beans.factory.config.BeanDefinition;
import cn.stimd.spring.beans.factory.support.AbstractBeanDefinition;
import cn.stimd.spring.beans.factory.support.BeanDefinitionRegistry;
import cn.stimd.spring.beans.factory.support.RootBeanDefinition;
import cn.stimd.spring.context.event.EventListenerMethodProcessor;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public class AnnotationConfigUtils {
    public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME = "internalAutowiredAnnotationProcessor";
    public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME = "internalConfigurationAnnotationProcessor";
    public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME = "internalCommonAnnotationProcessor";
    public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME = "internalEventListenerProcessor";

    /**
     * 注册解析相关注解的组件，包括BeanProcessor 和 BeanFactoryPostProcessor
     */
    public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
        //注册支持@Autowired和@Value注解的组件
        if(!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)){
            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME);
        }

        //注册支持@Configuration注解的组件
        if(!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)){
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME);
        }

        //注册支持@PostConstruct和@PreDestroy注解的组件
        if (!registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(InitDestroyAnnotationBeanPostProcessor.class);
            registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME);
        }

        //注册支持@EventListener注解的组件
        if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
            registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME);
        }
    }


    public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
        processCommonDefinitionAnnotations(abd, abd.getMetadata());
    }


    /**
     * 对Bean的注解进行处理，将注解上的信息转换成相应的BeanDefinition属性
     * 这些注解包括@Role、@Lazy、@Primary、@DependsOn等
     */
    public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition definition, AnnotatedTypeMetadata metadata) {
        if (metadata.isAnnotated(Primary.class.getName())) {
            definition.setPrimary(true);
        }

        if (definition instanceof AbstractBeanDefinition) {
            AbstractBeanDefinition abd = (AbstractBeanDefinition) definition;
            if(metadata.isAnnotated(Role.class.getName())){
                int role = attributesFor(metadata, Role.class).getNumber("value").intValue();
                abd.setRole(role);
            }
        }
    }


    //获取指定注解上的属性集合
    public static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, Class<?> annotationClass) {
        return attributesFor(metadata, annotationClass.getName());
    }

    static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, String annotationClassName) {
        return AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(annotationClassName, false));
    }


    private static void registerPostProcessor(BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
        definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(beanName, definition);
    }
}
